/*
 * MesoscopicNetworkBuilder.cpp
 *
 *  Created on: 21/11/2011
 *      Author: godinho
 */

#include <evolutive/impl/MesoscopicNetworkBuilder.h>
#include <localview/Network.h>
#include <localview/Node.h>
#include <localview/Edge.h>
#include <localview/Phase.h>
#include <localview/Link.h>
#include <Network.h>
#include <iostream>
#include <math.h>
#include <log.h>

MesoscopicNetworkBuilder::MesoscopicNetworkBuilder() {

}

MesoscopicNetworkBuilder::~MesoscopicNetworkBuilder() {
	// TODO Auto-generated destructor stub
}

Network* MesoscopicNetworkBuilder::lvNetwork2Mesoscopic(localview::Network* net) {
	mMesNet = new Network();

	localview::Node* n1;
	localview::Node* n2;
	localview::Edge* edg;
	localview::Phase* phase;
	localview::Link* link;
	std::string linkFrom;

	//Include nodes and edges
	for(unsigned int n = 0; n < net->getNodeCount(); n++) {
		n1 = net->getNode(n);
		mMesNet->addNode(n1->getId(), n1->getX(), n1->getY());
	}

	for(unsigned int n = 0; n < net->getNodeCount(); n++) {
		for(int e = 0; e < net->getNodeOutcomingEdgesCount(n); e++) {
			edg = net->getEdge(e);
			n1 = edg->getSource();
			n2 = edg->getTarget();

			mMesNet->addEdge(n1->getId(), n2->getId(), calcTravelTime(edg));
		}
	}

	//Include phases and links
	for(unsigned int n = 0; n < net->getNodeCount(); n++) {
		n1 = net->getNode(n);

		for(int p = 0; p < n1->getPhaseCount(); p++) {
			linkFrom = "";
			phase = n1->getPhase(p);

			//Links and flush
			std::vector<std::string> links;
			std::vector<int> flushs;

			for(int l = 0; l < phase->getLinkCount(); l++) {
				link = phase->getLink(l);
				if(phase->getStatus(l) == 'G') {
					links.push_back(link->getTo()->getId());
					flushs.push_back(getFlush(n1, link, net));
					linkFrom = link->getFrom()->getId();
				}
			}

			if(links.size() != 0) {
				mMesNet->addPhase(n1->getId(), linkFrom, links, flushs, phase->getDuration());
			}
		}
	}

	return mMesNet;
}

int MesoscopicNetworkBuilder::calcTravelTime(localview::Edge* e) {

	localview::Node* n1 = e->getSource();
	localview::Node* n2 = e->getTarget();

	float dx = n1->getX() - n2->getX();
	float dy = n1->getY() - n2->getY();

	float distance = sqrt( pow(dx,2) + pow(dy,2));

	return (int)round(distance / e->getMeanSpeed());
}

int MesoscopicNetworkBuilder::getFlush(localview::Node* node, localview::Link* link, localview::Network* net) {
	localview::Node* n1 = node;
	localview::Node* n2 = link->getTo();

	localview::Edge* e = net->getEdge(n1, n2);

	if(e == 0) {
		rsi::log("MesoscopicNetworkBuilder", __FILE__, __LINE__, "Cannot found an edge that binds %s and %s",
				n1->getId().c_str(), n2->getId().c_str());
	}

	return e->getFlush();
}
